package com.znh.entity;

import com.znh.common.PointPieceMapComparator;
import com.znh.common.Utils;
import com.znh.enums.PieceInitLocationEnum;
import com.znh.enums.PiecePlayerEnum;
import com.znh.main.GamePanel;
import com.znh.main.MainFrame;

import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.util.*;

/**
 * @version 1.0
 * @Author znh
 * @Date 2024/5/24 上午11:53
 * @注释 游戏规则
 */
public class GameRule {
    //游戏结束弹出框
    private static JOptionPane gameOverOptionPane;
    /**
     * 标示当前游戏是否结束
     */
    private static boolean IS_GAME_OVER = true;

    public static boolean getIsGameOver() {
        return IS_GAME_OVER;
    }

    public static void setIsGameOver(boolean isGameOver) {
        IS_GAME_OVER = isGameOver;
        if (isGameOver){
            JOptionPane.showMessageDialog(null,"game over!"+(CUR_ROUND==PiecePlayerEnum.RED?"black":"red")+" success!",
                    "Warning",JOptionPane.WARNING_MESSAGE);
        }
    }

    /**
     * 红方开局位置
     */
    public static PieceInitLocationEnum RED_LOCATION = PieceInitLocationEnum.UP;
    /**
     * 黑方开局位置
     */
    public static PieceInitLocationEnum BLACK_LOCATION = PieceInitLocationEnum.DOWN;
    /**
     * 先手：红
     */
    public static PiecePlayerEnum ON_THE_OFFENSIVE = PiecePlayerEnum.RED;
    /**
     * 当前回合
     */
    public static PiecePlayerEnum CUR_ROUND = ON_THE_OFFENSIVE;
    /**
     * 当前步数，-1表示未开局，0表示第1步
     */
    public static int CUR_STEP = -1;
    /**
     * 行棋记录
     */
    //public static ArrayList<Memo> MEMOS = new ArrayList<>();
    public static Memo MEMOS = new Memo(-1, GameRule.ON_THE_OFFENSIVE, null, null);
    /**
     * 当前步骤记录指针，永远指向当前步骤
     */
    public static Memo CUR_MEMO = MEMOS;
    /**
     * 第一次选中棋子
     */
    public static Piece SELECT_PIECE;
    /**
     * 棋谱信息
     */
    public static Manual MANUAL = new Manual();
    /**
     * 开局局面,0表示正常开局，1表示反转开局
     */
    public static String[] INIT_PHASE = new String[2];
    /**
     * 局面是否反转，true表示反转
     */
    private static boolean ISREVERSE = false;

    public static boolean getISREVERSE() {
        return ISREVERSE;
    }

    public static void setISREVERSE(boolean ISREVERSE) {
        GameRule.ISREVERSE = ISREVERSE;
        //反转位置表示
        RED_LOCATION = RED_LOCATION == PieceInitLocationEnum.DOWN ? PieceInitLocationEnum.UP : PieceInitLocationEnum.DOWN;
        BLACK_LOCATION = BLACK_LOCATION == PieceInitLocationEnum.DOWN ? PieceInitLocationEnum.UP : PieceInitLocationEnum.DOWN;
        MANUAL.setRedLocation(RED_LOCATION.ordinal());
        //填充INIT_PHASE
        if (INIT_PHASE[1] == null) {
            //开局局面反转
            Utils.reversePhaseMap(INIT_POINT_PIECE_MAP);
            INIT_PHASE[1] = Utils.phaseToString(INIT_POINT_PIECE_MAP);
        }
        //填充棋谱开局局面
        MANUAL.setInitPhase(INIT_PHASE[ISREVERSE ? 1 : 0]);

        UIManager.put("OptionPane.messageFont",new Font("Serif", Font.PLAIN, 20));
    }

    public final static String PIECES_NAME[] = {"che", "ma", "xiang", "shi", "boss", "shi", "xiang", "ma", "che", "pao", "pao",
            "bing", "bing", "bing", "bing", "bing"};
    //棋子名称对应缩写
    public final static HashMap<String, String> PIECE_NAME_ANAME = new HashMap<>();
    //棋子缩写对应名称
    public final static HashMap<String, String> PIECE_ANAME_NAME = new HashMap<>();

    static {
        PIECE_NAME_ANAME.put("boss", "1");
        PIECE_NAME_ANAME.put("shi", "2");
        PIECE_NAME_ANAME.put("xiang", "3");
        PIECE_NAME_ANAME.put("ma", "4");
        PIECE_NAME_ANAME.put("che", "5");
        PIECE_NAME_ANAME.put("pao", "6");
        PIECE_NAME_ANAME.put("bing", "7");

        PIECE_ANAME_NAME.put("1", "boss");
        PIECE_ANAME_NAME.put("2", "shi");
        PIECE_ANAME_NAME.put("3", "xiang");
        PIECE_ANAME_NAME.put("4", "ma");
        PIECE_ANAME_NAME.put("5", "che");
        PIECE_ANAME_NAME.put("6", "pao");
        PIECE_ANAME_NAME.put("7", "bing");

        MANUAL.setRedLocation(RED_LOCATION.ordinal());
    }

    /**
     * //棋盘初始棋子位置
     */
    public final static HashMap<PieceInitLocationEnum, Point[]> LOCATION_POINT = new HashMap<PieceInitLocationEnum, Point[]>() {{
        put(PieceInitLocationEnum.UP, new Point[]{
                new Point(1, 1), new Point(2, 1), new Point(3, 1), new Point(4, 1), new Point(5, 1),
                new Point(6, 1), new Point(7, 1), new Point(8, 1), new Point(9, 1),
                new Point(2, 3), new Point(8, 3),
                new Point(1, 4), new Point(3, 4), new Point(5, 4), new Point(7, 4), new Point(9, 4),
        });
        put(PieceInitLocationEnum.DOWN, new Point[]{
                new Point(1, 10), new Point(2, 10), new Point(3, 10), new Point(4, 10), new Point(5, 10),
                new Point(6, 10), new Point(7, 10), new Point(8, 10), new Point(9, 10),
                new Point(2, 8), new Point(8, 8),
                new Point(1, 7), new Point(3, 7), new Point(5, 7), new Point(7, 7), new Point(9, 7),
        });
    }};
    /**
     * 当前局面，逻辑坐标->棋子，按坐标排序
     */
    //由于treemap比较器使用了匿名内部类，这个内部类没有实现序列化接口，因此无法序列化
//    public static TreeMap<Point, Piece> POINT_PIECE_MAP = new TreeMap<>((o1, o2) -> {
//        if (o1.x > o2.x) return 1;
//        else if (o1.x < o2.x) return -1;
//        else if (o1.y > o2.y) return 1;
//        else if (o1.y < o2.y) return -1;
//        else return 0;
//    });
    public static TreeMap<Point, Piece> POINT_PIECE_MAP = new TreeMap<>(new PointPieceMapComparator());

    /**
     * 当前局面，阵营->(名称->棋子)
     */
    public static HashMap<PiecePlayerEnum, HashMap<String, HashSet<Piece>>> NAME_PIECE_MAP = new HashMap<PiecePlayerEnum, HashMap<String, HashSet<Piece>>>() {{
        put(PiecePlayerEnum.RED, new HashMap<>());
        put(PiecePlayerEnum.BLACK, new HashMap<>());
    }};

    /**
     * 开局局面，逻辑坐标->棋子
     */
    public static HashMap<Point, Piece> INIT_POINT_PIECE_MAP = new HashMap<>();


    /**
     * 交换回合
     */
    public static void changeRound() {
        CUR_ROUND = CUR_ROUND == PiecePlayerEnum.RED ? PiecePlayerEnum.BLACK : PiecePlayerEnum.RED;
        //清除分叉按钮
        MainFrame.clearForkBtn();
    }

    /**
     * 添加行棋记录
     *
     * @param curPlayer   当前回合轮到谁
     * @param actionPiece 行动的棋子
     * @param atePiece    被吃的棋子
     * @param targetPoint 目标坐标
     */
    public static void addMemo(PiecePlayerEnum curPlayer, Piece actionPiece, Piece atePiece, Point targetPoint) {
        CUR_STEP += 1;
        boolean isAddChildren = true;
        Memo memo = new Memo(CUR_STEP, curPlayer, actionPiece, atePiece, targetPoint);
        ArrayList<Memo> children = CUR_MEMO.getChildren();
        if (children != null) {
            for (Memo child : children) {
                if (child.equals(memo)) {
                    memo = child;
                    isAddChildren = false;
                    break;
                }
            }
        }
        if (isAddChildren) {
            CUR_MEMO.addChildren(memo);
        }
        //指向当前步骤
        CUR_MEMO = memo;
    }

    /**
     * 悔棋
     */
    public static void regret() throws Exception {
        //把目标从棋盘上移除
        removeCurPhaseMap(POINT_PIECE_MAP.get(CUR_MEMO.getTargetPoint()));
        //将行动前棋子位置还原到棋盘上
        Piece actionPiece = Utils.deepClone(CUR_MEMO.getActionPiece());
        Piece atePiece = Utils.deepClone(CUR_MEMO.getAtePiece());
        addCurPhaseMap(actionPiece);
        if (atePiece != null) {
            addCurPhaseMap(atePiece);
        }
        //全局步数回退
        CUR_STEP -= 1;
        //指向上一步
        CUR_MEMO = CUR_MEMO.getParent();
        //交换回合
        changeRound();
        //清除第一次选中棋子
        SELECT_PIECE = null;
        //获取当前局面评论
        Comment.phase=Utils.phaseToString(POINT_PIECE_MAP);
        Comment.getComment();
        //判断是否将军
        if (!GameRule.getIsGameOver()&&GameRule.NAME_PIECE_MAP.get(GameRule.CUR_ROUND).get("boss").stream()
                .anyMatch(boss -> ((Boss) boss).isNextEat())){
            JOptionPane.showMessageDialog(null,"jiangjun",
                    "Warning",JOptionPane.WARNING_MESSAGE);
        }
    }

    /**
     * 前进
     *
     * @param index 选择前进哪一步
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static void forward(int index) throws IOException, ClassNotFoundException {
        ArrayList<Memo> children = Utils.deepClone(CUR_MEMO.getChildren());
        Memo memo = children.get(index);
        Piece actionPiece = memo.getActionPiece();
        Point targetPoint = memo.getTargetPoint();
        Piece atePiece = memo.getAtePiece();
        if (atePiece != null) {
            removeCurPhaseMap(atePiece);
        }
        removeCurPhaseMap(actionPiece);
        actionPiece.setPoint(targetPoint);
        addCurPhaseMap(actionPiece);
        //全局步数前进一步
        CUR_STEP += 1;
        //指针指向下一步
        CUR_MEMO = CUR_MEMO.getChildren().get(index);
        //交换回合
        changeRound();
        //清除第一次选中棋子
        SELECT_PIECE = null;
        //获取当前局面评论
        Comment.phase=Utils.phaseToString(POINT_PIECE_MAP);
        Comment.getComment();
        //判断游戏是否结束
        GameRule.setIsGameOver(GameRule.isGameOver());
        //判断是否将军
        if (!GameRule.getIsGameOver()&&GameRule.NAME_PIECE_MAP.get(GameRule.CUR_ROUND).get("boss").stream()
                .anyMatch(boss -> ((Boss) boss).isNextEat())){
            JOptionPane.showMessageDialog(null,"jiangjun",
                    "Warning",JOptionPane.WARNING_MESSAGE);
        }
    }

    /**
     * 翻转所有棋子、记录坐标
     */
    public static void reverse() {
        //反转当前局面
        Utils.reversePhaseMap(POINT_PIECE_MAP);
        setISREVERSE(!getISREVERSE());
        //行棋记录反转
        MEMOS.reverse();
    }

    /**
     * 当前局面添加操作
     *
     * @param piece
     */
    public static void addCurPhaseMap(Piece piece) {
        Point point = piece.getPoint();
        POINT_PIECE_MAP.put(point, piece);
        PiecePlayerEnum player = piece.getPlayer();
        String name = piece.getName();
        HashMap<String, HashSet<Piece>> playerMap = NAME_PIECE_MAP.get(player);
        if (playerMap.containsKey(name)) {
            playerMap.get(name).add(piece);
        } else {
            HashSet<Piece> set = new HashSet<>();
            set.add(piece);
            playerMap.put(name, set);
        }
    }

    /**
     * 当前局面删除操作
     *
     * @param piece
     */
    public static void removeCurPhaseMap(Piece piece) {
        Point point = piece.getPoint();
        POINT_PIECE_MAP.remove(point);
        PiecePlayerEnum player = piece.getPlayer();
        String name = piece.getName();
        NAME_PIECE_MAP.get(player).get(name).remove(piece);
    }

    /**
     * 判断当前游戏是否结束
     * @return true:游戏结束
     */
    public static boolean isGameOver() {
        HashMap<String, HashSet<Piece>> curPlayerNamePieceMap = Utils.deepClone(NAME_PIECE_MAP.get(CUR_ROUND));
        //无子可走即为游戏失败
        return !curPlayerNamePieceMap.entrySet().stream().anyMatch(namePieces -> namePieces.getValue().stream().anyMatch(piece -> {
                    for (int x = 1; x < 10; x++) {
                        for (int y = 1; y < 11; y++) {
                            if (piece.simulateMove(new Point(x, y))) {
                                return true;
                            }
                        }
                    }
                    return false;
                })
        );
    }
}